package game.johan.engine;
/*
Copyright (C) 2013 Johan Ceuppens

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/


import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.awt.*;
import javax.swing.*;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Event;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.GraphicsEnvironment;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.Timer;

//FIXME 2 singletons for _canvas & _canvasThreand & Holders
public class EngineBase extends JPanel implements ActionListener
{
	private int _multicore = 2;//FIXME changes at runtime
	private GameObjectThread _drawthread;
	private GameObjectUpdateThread _updatethread;
	
	private GameThreadSingleCore _gamethreadsinglecore;

	private String fileprefixpics = "./pics/";	
	private Canvas _canvas;
	private int _screenw;
	private int _screenh;
	private Surface _screensurface;
	private SurfaceList _surfacelist;
	private DrawMethodList _drawmethodlist;
	private AIMachine _aimachine;

	private SurfaceTileMap _surfacetilemap = new SurfaceTileMap();
	private int _xmapoffset = 0;
	private int _ymapoffset = 0;
	public EngineBase() {
		
		_screenw = 640;
		_screenh = 480;
		_screensurface = new Surface(0,0,_screenw,_screenh);
			
		_surfacelist = new SurfaceList(this);
		_drawmethodlist = new DrawMethodList(this);	
		Timer timer;

        	addKeyListener(new EngineBaseAdapter());
        	setFocusable(true);
	
        	setBackground(Color.white);
        	setDoubleBuffered(true);

        	timer = new Timer(40, this);
        	timer.start();

	}

	/* NOTE that the offsets get transmogrified inside the surfacetile
	*/
    	class EngineBaseAdapter extends KeyAdapter {
        public void keyReleased(KeyEvent e) {
		_xmapoffset = 0;
		_ymapoffset = 0;
	} 
      

        public void keyPressed(KeyEvent e) {
          int key = e.getKeyCode();

	   	if (key == KeyEvent.VK_LEFT) {
			_xmapoffset -= 10;
		} else if (key == KeyEvent.VK_RIGHT) {
			_xmapoffset += 10;
		} else if (key == KeyEvent.VK_UP) {
			_ymapoffset -= 10;
		} else if (key == KeyEvent.VK_DOWN) {
			_ymapoffset += 10;
		}
		}
	};
    	public void actionPerformed(ActionEvent e) {
        	repaint();  
    	}

	//FIXME not at runtime
	public void setToSingleCore() {
		_multicore = 1;
	}
	
	public void setToMultiCore() {
		_multicore = 1;
	}
	
  public void start() {
	  
	  if (_multicore == 2) {
		  
	  /*
	   * async game event handler, with GameEvent instances for events
	   * This might be changed to multiple handlers for (multi-core) systems
	   */
      final GameObjectEventSource _draweventsource = new GameDrawEventSource(this);
      final GameEventHandler _draweventhandler = new GameDrawEventHandler();
      _draweventsource.addObserver(_draweventhandler);

      // starts the drawing event thread
      _drawthread = new GameObjectThread(this,_draweventsource);
      _drawthread.start();
      
      final GameObjectEventSource _updateeventsource = new GameDrawEventSource(this);
      final GameEventHandler _updateeventhandler = new GameDrawEventHandler();
      _updateeventsource.addObserver(_updateeventhandler);

      // starts the update event thread
      _updatethread = new GameObjectUpdateThread(this,_draweventsource);
      _updatethread.start();

	  } else {
		  
	  final GameEventSource _eventsource = new GameEventSource(/*this*/);
	      final GameEventHandler _eventhandler = new GameEventHandler();
	      _eventsource.addObserver(_eventhandler);

	      // starts the drawing event thread
	      _gamethreadsinglecore = new GameThreadSingleCore(this,_eventsource);
	      _gamethreadsinglecore.start();
		  
	  }
  }
  
  public void renderscreensurface() {
	  	_surfacelist.drawOn(_screensurface);
	  	_screensurface.render(this);
  }

  public void update() {
	  _aimachine.update();
  }
  
  public void end() {

	  if (_multicore == 2) {
	  
	  boolean retry = true;
	  _drawthread.setRunning(false);
	  _updatethread.setRunning(false);
	  while(retry) {
	  try {
		  _drawthread.join();
		  _updatethread.join();
		  retry = false;
	  	} catch (InterruptedException e) {
	    	System.out.println("Message "+e.getMessage());
	    	e.printStackTrace();
	  	}
	  }
	  } else {
		  boolean retry = true;
		  _gamethreadsinglecore.setRunning(false);
		  while(retry) {
		  try {
			  _gamethreadsinglecore.join();
			  retry = false;
		  	} catch (InterruptedException e) {
		    	System.out.println("Message "+e.getMessage());
		    	e.printStackTrace();
		  	}
		  }  
		  
		  
	  }
  }
  /** Called when the activity is first created. */
//  @Override
//  public void onCreate(Bundle savedInstanceState) {
//      super.onCreate(savedInstanceState);
//      setContentView(R.layout.main);
//      ImageView image = (ImageView) findViewById(R.id.test_image);
//      Bitmap bMap = BitmapFactory.decodeFile("/sdcard/test2.png");
//      image.setImageBitmap(bMap);
//  }

  public void paint(Graphics g)
    {
      	Graphics2D g2d = (Graphics2D) g;
      	g2d.setColor(Color.black);
      	g2d.fillRect(0, 0, 640, 480);
	//render screensurface
	renderscreensurface();

	//NOTE surfaces only render before the next loop of the _drawmethodslist
//example code
//	ImageTile t0 = new ImageTile0("t16tiles.png");//320x853
//	g2d.drawImage(t0.get(),0,0,this);
//	SurfaceTile st0 = new SurfaceTile("stub.png",100,0,64,64);
//	Surface s0 = st0.get();
//	s0.setRegion(0,0,48,48);
//	s0.render(this);

	while (true) { 
		SurfaceTile surftile = _surfacetilemap.get();
		if (surftile == null)
			break;
		else {
			if (_xmapoffset != 0 || _ymapoffset != 0)
				surftile.setxy(surftile.getx()+_xmapoffset,surftile.gety()+_ymapoffset);
			surftile.get().render(this);
		}
	} 

	//Image img = new ImageIcon(fileprefixpics+"t16tiles.png").getImage();
	//g2d.drawImage(img,0,0,this);	
	//draw 
	int idx = 0;
	for ( ; idx < _drawmethodlist.size(); idx++ )
		_drawmethodlist.get(idx).draw(g2d, this);
	_drawmethodlist.clear();

  	Toolkit.getDefaultToolkit().sync();
      	g2d.dispose();
    } 

  protected void drawOnPanel(DrawMethod dm) {
	//done before df.init();
	//_drawmethods.add(df.f(g2d,img,0,0,this));
	_drawmethodlist.add(dm);
  }
  
  public void setscreenwh(int w, int h) {
	  _screenh = h;
	  _screenw = w;
  }
 }
